
/*************************************************************************
 *
 *    Used with ICCARM and AARM.
 *
 *    (c) Copyright IAR Systems 2010
 *
 *    File name   : sd_ll_spi.c
 *    Description : SD/MMC low level SPI driver
 *
 *    History :
 *    1. Date        : June, 2010
 *       Author      : Stoyan Choynev
 *       Description : Initial revition
 *
 *	2. Data	  : Nov. 18 ,2013
 	  Author	  : Mark GAO
 	  Description  : Modify data type, add some function
 *    $Revision: 42092 $
 *
 **************************************************************************/
//#include "board.h"
#include "sd_ll_spi.h"
//#include "timer.h"

/*****************************************************************************/
/* Global variable definitions (declared in header file with 'extern')       */
/*****************************************************************************/

/*************************************************************************
 * Function Name: SdPowerOn
 * Parameters: none
 * Return: none
 *
 * Description: Set power off state
 *
 *************************************************************************/
void SdPowerOn (void)
{
	/* There is no power control on board.  */
}
/*************************************************************************
 * Function Name: SdPowerOff
 * Parameters: none
 * Return: none
 *
 * Description: Set power off state
 *
 *************************************************************************/
void SdPowerOff (void)
{
	/* There is no power control on board.  */
}
/*************************************************************************
 * Function Name: SdChipSelect
 * Parameters: boolean_t Select
 * Return: none
 *
 * Description: SD/MMC Chip select control
 * Select = true  - Chip is enable
 * Select = false - Chip is disable
 *
 *************************************************************************/
void SdChipSelect (boolean_t Select)
{
	SD_CS_PDOR &= ~(SD_CS);
	if(Select)
	{
		SD_CS_PDOR &= ~(SD_CS);
	}
	else
	{
		//wait transmission ends
		while(!SD_CSIO_CH->SSR_f.TBI);//while(!bFM3_MFS5_CSIO_SSR_TBI);
		SD_CS_PDOR |= (SD_CS);
		SdTranserByte(0xFF);
	}

}
/*************************************************************************
 * Function Name: SdPresent
 * Parameters: none
 * Return: boolean_t - true cart present
 *                 - false cart no present
 *
 * Description: SD/MMC present check
 *
 *************************************************************************/
boolean_t SdPresent (void)
{
   return((SD_CP_PDIR & SD_CP) == 0);
}

/*************************************************************************
 * Function Name: SdWriteProtect
 * Parameters: none
 * Return: boolean_t - true cart is protected
 *                 - false cart no protected
 *
 * Description: SD/MMC Write protect check
 *
 *************************************************************************/
boolean_t SdWriteProtect (void)
{
	/* there is no Write Protect on board */
	// return((SD_WP_PDIR & SD_WP) != 0);
	return(FALSE);
}


/*************************************************************************
 * Function Name: SdSetClockFreq
 * Parameters: uint32_t Frequency
 * Return: uint32_t
 *
 * Description: Set SPI clock frequency
 *
 *************************************************************************/
uint32_t SdSetClockFreq (uint32_t Frequency)
{
	uint32_t Div;

	uint32_t PCLK = GetBaseClock()/(1<<(FM3_CRG->APBC2_PSR & 0x03));

	for(Div = 3; Div < ((1<<15)-1); Div++)
	{
		if(Frequency * (Div+1) > PCLK)
		{
		  break;
		}
	}

	SD_CSIO_CH->BGR = Div; // FM3_MFS5_CSIO->BGR = Div;
	/*Software reset*/
	SD_CSIO_CH->SCR_f.UPCL = 1; // bFM3_MFS5_CSIO_SCR_UPCL = 1;
	/*Return real frequency*/
	return(PCLK/(Div+1));
}

/*************************************************************************
 * Function Name: SdInit
 * Parameters: none
 * Return: none
 *
 * Description: Init SPI, Cart Present, Write Protect and Chip select pins
 *
 *************************************************************************/
void SdInit(void)
{

	//SPI : MFS5 ch2,
	/* MFS5 ch2: SIN5_2:P36, SOT5_2:P37 SCK5_2:P38 */
	SD_CSIO_PFR |= SD_CSIO_MASK;
	SD_CSIO_EPFR = SD_CSIO_EPFR & (~(SD_CSIO_EPFR_MASK)) | (SD_CSIO_EPFR_VAL);
	/* Chip select */
	/*Select CPIO function*/
	SD_CS_PFR &= ~(SD_CS);
	/*Set Pin to high level*/
	SD_CS_PDOR |= SD_CS;
	/*Make pin output*/
	SD_CS_DDR |= SD_CS;

	/* Cart present */
	/*Select CPIO function*/
	SD_CP_PFR &= ~(SD_CP);
	/*Make pin input*/
	SD_CP_DDR &= ~(SD_CP);

	/*SPI init*/
	SD_CSIO_CH->SCR_f.UPCL = 1; // software reset

	SD_CSIO_CH->SMR = (2<<5) |	/*clock sync mode*/
					  (0<<4) |  /*no wake up*/
					  (1<<3) |  /*Signal level "LOW" detection format*/
					  (1<<2) |  /*MSB firs*/
					  (1<<1) |  /*Enables a serial clock output*/
					  (1<<0) ;  /*Enables a serial data output*/

	SD_CSIO_CH->SCR = (0<<6) |  /*Master mode*/
					  (1<<5) |  /*SPI mode*/
					  (0<<2) |  /*Disable interrupts*/
					  (0<<1) |  /*Disable RX */
					  (0<<0) ;  /*Disable TX */

	SD_CSIO_CH->ESCR =(0<<7) |	/*SOUT LOW*/
					  (0<<3) |  /*continuous SCLK*/
					  (0<<0) ;  /*8-bit*/

	SD_CSIO_CH->SSR = (1<<7) ;  /*Clear receive error status*/

	SdSetClockFreq(IdentificationModeClock);

	/*DMA initialization*/
	/*Transmit channel*/
	bFM3_DMAC_DMACR_DE = 0;   /*Disabler all transfers*/
	FM3_DMAC->DMACA0 = (0<<31) |  /*Channel 0 disable*/
					   (0<<30) |  /*Clear Pause bit*/
					   (0<<29) |  /*Clear Software trigger*/
					   ((0x20 | 23)<<23)|  /*Sending interrupt signal from MFS ch.1-->15,,-->23(MFS 5)*/
					   (0<<16) |  /*BC 1*/
					   (0<<0)  ;  /*TC 1*/
	/*Channel 0 disable*/
	FM3_DMAC->DMACB0 = (2<<28) |  /*Demand transfer mode*/
					 (0<<26) |  /*8-Bit transfer*/
					 (0<<25) |  /*Increments the transfer source address*/
					 (1<<24) |  /*Fixes the transfer destination address.*/
					 (0<<23) |  /*Disables the reload function.*/
					 (0<<22) |  /*Disables the reload function of the transfer source address.*/
					 (0<<21) |  /*Disables the reload function of the transfer destination address.*/
					 (0<<20) |  /*Disables error interrup.*/
					 (0<<19) |  /*Disables interrupt.*/
					 (0<<16) |  /*status clear*/
					 (0<<0) ;   /*Clears EB upon completion of the transfer.*/

	/*The transmission interrupt of the MFS ch. 1 is output as a transfer
	request to the DMAC.*/
	// bFM3_INTREQ_DRQSEL_DRQSEL15 = 1;
	// bFM3_INTREQ_DRQSEL_DRQSEL19 = 1;
    bFM3_INTREQ_DRQSEL_DRQSEL23 = 1;
	/*Receive channel*/
	FM3_DMAC->DMACA1 = (0<<31) |  /*Channel 1 disable*/
		   (0<<30) |  /*Clear Pause bit*/
		   (0<<29) |  /*Clear Software trigger*/
		   ((0x20 | 22)<<23)|  /*Receiving interrupt signal from MFS ch.1  14-->22(mfs 5)*/
		   (0<<16) |  /*BC 1*/
		   (0<<0)  ;  /*TC 1*/
	/*Channel 0 disable*/

	FM3_DMAC->DMACB1 = (2<<28) |  /*Demand transfer mode*/
		   (0<<26) |  /*8-Bit transfer*/
		   (1<<25) |  /*Fixes the transfer source address*/
		   (0<<24) |  /*Increments the transfer destination address.*/
		   (0<<23) |  /*Disables the reload function.*/
		   (0<<22) |  /*Disables the reload function of the transfer source address.*/
		   (0<<21) |  /*Disables the reload function of the transfer destination address.*/
		   (0<<20) |  /*Disables error interrupt.*/
		   (0<<19) |  /*Disables interrupt.*/
		   (0<<16) |  /*status clear*/
		   (0<<0) ;   /*Clears EB upon completion of the transfer.*/

	/*The reception interrupt of the MFS ch. 1 is output as a transfer
	request to the DMAC.*/
	//  bFM3_INTREQ_DRQSEL_DRQSEL14 = 1;
	// bFM3_INTREQ_DRQSEL_DRQSEL18 = 1;
    bFM3_INTREQ_DRQSEL_DRQSEL22 = 1;
	bFM3_DMAC_DMACR_DE = 1;   /*Enable all transfers*/
	bFM3_DMAC_DMACR_PR=1; //PR [28]: Rotated mode
}

/*************************************************************************
 * Function Name: SdTranserByte
 * Parameters: uint8_t ch
 * Return: uint8_t
 *
 * Description: Read byte from SPI
 *
 *************************************************************************/
uint8_t SdTranserByte (uint8_t ch)
{
	volatile uint8_t read;

	while(!SD_CSIO_CH->SSR_f.TBI);
	SD_CSIO_CH->SCR_f.RXE = 1;  //bFM3_MFS3_CSIO_SCR_RXE = 1;
	SD_CSIO_CH->SCR_f.TXE = 1;	//bFM3_MFS3_CSIO_SCR_TXE = 1;

	SD_CSIO_CH->TDR = ch;
	//while(!bFM3_MFS3_CSIO_SSR_RDRF);
    while(!SD_CSIO_CH->SSR_f.RDRF);

	read = SD_CSIO_CH->RDR & 0xFF;

	SD_CSIO_CH->SCR_f.RXE = 0;	//bFM3_MFS3_CSIO_SCR_RXE = 0;
	SD_CSIO_CH->SCR_f.TXE = 0;	//bFM3_MFS3_CSIO_SCR_TXE = 0;

	return read;
}

/*************************************************************************
 * Function Name: SdSendBlock
 * Parameters: uint8_t* pData, uint32_t Size
 *
 * Return: void
 *
 * Description: Read byte from SPI
 *
 *************************************************************************/
void SdSendBlock (uint8_t* pData, uint32_t Size)
{
	SD_CSIO_CH->SCR_f.TXE = 1;	//bFM3_MFS3_CSIO_SCR_TXE = 1;
	SD_CSIO_CH->SCR_f.RXE = 0;	//bFM3_MFS3_CSIO_SCR_RXE = 0;

	FM3_DMAC->DMACSA0 = (uint32_t)pData;
	/*Inclement source*/
	bFM3_DMAC_DMACB0_FS = 0;
	FM3_DMAC->DMACDA0 = (uint32_t)(&(SD_CSIO_CH->TDR));
	FM3_DMAC->DMACA0 = (FM3_DMAC->DMACA0 & 0xFFFF0000) | (Size-1);  /* TC */
	bFM3_DMAC_DMACA0_EB = 1;

	/*TX Interrupt enable*/
	SD_CSIO_CH->SCR_f.TIE = 1;	//bFM3_MFS3_CSIO_SCR_TIE = 1;
	/*wait transfer end*/
	while(bFM3_DMAC_DMACA0_EB);
	/*DMA Interrupt enable*/
	SD_CSIO_CH->SCR_f.TIE = 0;	//bFM3_MFS3_CSIO_SCR_TIE = 0;
}

/*************************************************************************
 * Function Name: SdReceiveBlock
 * Parameters: uint8_t* pData, uint32_t Size
 *
 * Return: void
 *
 * Description: Read byte from SPI
 *
 *************************************************************************/
void SdReceiveBlock (uint8_t* pData, uint32_t Size)
{
    volatile int dummy = 0xFF;

    SD_CSIO_CH->SCR_f.TXE = 1;	//bFM3_MFS3_CSIO_SCR_TXE = 1;
    SD_CSIO_CH->SCR_f.RXE = 1;	//bFM3_MFS3_CSIO_SCR_RXE = 1;


    FM3_DMAC->DMACSA1 = (uint32_t)(&(SD_CSIO_CH->RDR));
    FM3_DMAC->DMACDA1 = (uint32_t)pData;
    FM3_DMAC->DMACA1 = (FM3_DMAC->DMACA1 & 0xFFFF0000) | (Size-1);  /* TC */
    bFM3_DMAC_DMACA1_EB = 1;

    /*RX Interrupt enable*/
    SD_CSIO_CH->SCR_f.RIE = 1;	//bFM3_MFS3_CSIO_SCR_RIE = 1;
    /*Dummy write via DMA*/
    FM3_DMAC->DMACSA0 = (uint32_t)&dummy;
    /*Fixed source*/
    bFM3_DMAC_DMACB0_FS = 1;
    FM3_DMAC->DMACDA0 = (uint32_t)(&(SD_CSIO_CH->TDR));
    FM3_DMAC->DMACA0 = (FM3_DMAC->DMACA0 & 0xFFFF0000) | (Size-1);  /* TC */
    bFM3_DMAC_DMACA0_EB = 1;
    /*TX Interrupt enable*/
    SD_CSIO_CH->SCR_f.TIE = 1;	//bFM3_MFS3_CSIO_SCR_TIE = 1;
    /*wait transfer end*/
    while(bFM3_DMAC_DMACA0_EB);
    /*DMA Interrupt enable*/
    SD_CSIO_CH->SCR_f.TIE = 0;	//bFM3_MFS3_CSIO_SCR_TIE = 0;
    /*wait transfer end*/
    while(bFM3_DMAC_DMACA1_EB);
    /*DMA Interrupt enable*/
    SD_CSIO_CH->SCR_f.RIE = 0;	//bFM3_MFS3_CSIO_SCR_RIE = 0;
}

/*************************************************************************
 * Function Name: SdDly_1ms
 * Parameters: uint32_t Delay
 * Return: none
 *
 * Description: Delay [msec]
 *
 *************************************************************************/
void SdDly_1ms (uint32_t Delay)
{
  /*volatile uint32_t i;
  for(;Delay;--Delay)
  {
    for(i = SD_DLY_1MSEC;i;--i);
  }*/
    //dly1ms_count = Delay;
    //while(dly1ms_count);

}


